using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace Gko.Utils
{
	internal class NativeVFTable
	{
		internal readonly NativeInterface Interface;

		[StructLayout(LayoutKind.Sequential)]
		private struct FunctionPtrWrapper
		{
			[MarshalAs(UnmanagedType.FunctionPtr)]
			private Delegate function;

			internal static IntPtr GetMethodPtr(Delegate function)
			{
				using (var pStruct = UnmanagedMemoryBlock.AllocateCoTaskMem<FunctionPtrWrapper>()) {
					Marshal.StructureToPtr(new FunctionPtrWrapper(function), pStruct, false);
					return Marshal.ReadIntPtr(pStruct);
				}
			}

			private FunctionPtrWrapper(Delegate function)
			{
				this.function = function;
			}
		}

		internal NativeVFTable(NativeInterface iface)
		{
			this.Interface = iface;
		}

		internal TDelegate GetMethod<TDelegate>(int index) where TDelegate : class
		{
			return (TDelegate)this.GetMethod(index, typeof(TDelegate));
		}

		internal object GetMethod(int index, Type delegateType)
		{
			return Marshal.GetDelegateForFunctionPointer(this.Interface[index], delegateType);
		}

		internal void SetMethod(Delegate method, int index)
		{
			this.Interface.SetMethod(index, FunctionPtrWrapper.GetMethodPtr(method));
		}

	}
}